package engine.util;

import engine.scene.Tri;
import engine.scene.TriGroup;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import math.vector.vec2f;
import math.vector.vec3f;
import math.vector.vec3i;

public class ModelUtil
{
    
    private static final String FILE_PATH = "models/";
    private static final String FILE_TYPE = ".obj";
    
    public static final int MAX_TRIS = 65536; // 2^16
    
    //<editor-fold defaultstate="collapsed" desc="Singleton">
    private static ModelUtil singleton;
    
    public static ModelUtil get()
    {
        if (singleton == null)
        {
            singleton = new ModelUtil();
        }
        return singleton;
    }
    //</editor-fold>
    
    
    private ModelUtil()
    {
    }
    
    public TriGroup loadModelOBJ(String fileName)
    {
        vec3i[] indVerts = new vec3i[ModelUtil.MAX_TRIS];
        vec3i[] indNorms = new vec3i[ModelUtil.MAX_TRIS];
        vec3i[] indTexCoords = new vec3i[ModelUtil.MAX_TRIS];
        vec3f[] verts = new vec3f[ModelUtil.MAX_TRIS * 3];
        vec3f[] norms = new vec3f[ModelUtil.MAX_TRIS * 3];
        vec2f[] texCoords = new vec2f[ModelUtil.MAX_TRIS * 3];
        int fi = 0;
        int vi = 0;
        int ni = 0;
        int tci = 0;
        
        BufferedReader reader = null;
        String line = null;
        try
        {
            reader = new BufferedReader(
                new FileReader(
                    new File(
                        ModelUtil.FILE_PATH + fileName + ModelUtil.FILE_TYPE
                    )
                )
            );
            line = reader.readLine();
        }
        catch (FileNotFoundException ex)
        {
            System.out.println(ex);
            System.exit(1);
        }
        catch (IOException ex)
        {
            System.out.println(ex);
            System.exit(1);
        }
        while (line != null)
        {
            if (line.startsWith("v "))
            {
                String[] split = line.split(" ");
                float vx = toFloat(split[1]);
                float vy = toFloat(split[2]);
                float vz = toFloat(split[3]);
                verts[vi++] = new vec3f(vx, vy, vz);
            }
            else if (line.startsWith("vt "))
            {
                String[] split = line.split(" ");
                float s = toFloat(split[1]);
                float t = toFloat(split[2]);
                texCoords[tci++] = new vec2f(s, t);
            }
            else if (line.startsWith("vn "))
            {
                String[] split = line.split(" ");
                float nx = toFloat(split[1]);
                float ny = toFloat(split[2]);
                float nz = toFloat(split[3]);
                norms[ni++] = new vec3f(nx, ny, nz);
            }
            else if (line.startsWith("f "))
            {
                String[] split = line.split(" ");
                String[] vert0 = split[1].split("/");
                String[] vert1 = split[2].split("/");
                String[] vert2 = split[3].split("/");
                indVerts[fi] = new vec3i(
                    toInt(vert0[0]) - 1, toInt(vert1[0]) - 1, toInt(vert2[0]) - 1
                );
                indNorms[fi] = new vec3i(
                    toInt(vert0[2]) - 1, toInt(vert1[2]) - 1, toInt(vert2[2]) - 1
                );
                indTexCoords[fi] = new vec3i(
                    toInt(vert0[1]) - 1, toInt(vert1[1]) - 1, toInt(vert2[1]) - 1
                );
                fi++;
            }
            try
            {
                line = reader.readLine();
            }
            catch (IOException ex)
            {
                System.out.println(ex);
                System.exit(1);
            }
        }
        Tri[] arrTris = new Tri[fi];
        for (int i = 0; i < fi; i++)
        {
            arrTris[i] = new Tri();
            arrTris[i].setVertexAt(0, verts[indVerts[i].x]);
            arrTris[i].setVertexAt(1, verts[indVerts[i].y]);
            arrTris[i].setVertexAt(2, verts[indVerts[i].z]);
            
            arrTris[i].setNormalAt(0, norms[indNorms[i].x]);
            arrTris[i].setNormalAt(1, norms[indNorms[i].y]);
            arrTris[i].setNormalAt(2, norms[indNorms[i].z]);
            
            arrTris[i].setTexCoordAt(0, texCoords[indTexCoords[i].x]);
            arrTris[i].setTexCoordAt(1, texCoords[indTexCoords[i].y]);
            arrTris[i].setTexCoordAt(2, texCoords[indTexCoords[i].z]);
        }
        TriGroup triGroup = new TriGroup(arrTris);
        return triGroup;
    }
    
    private float toFloat(String dataString)
    {
        return Float.valueOf(dataString);
    }
    
    private int toInt(String dataString)
    {
        return Integer.valueOf(dataString);
    }
    
}
